﻿using Candy.Infrastructure;
using Candy.Model;
using Candy.Web.Data;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Threading;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Windows.Controls;

namespace Candy.ViewModel
{
    public class SettingsViewModel : CandyViewModelBase
    {
        private bool _isBusy;
        public bool IsBusy
        {
            get
            {
                return _isBusy;
            }
            set
            {
                _isBusy = value;
                RaisePropertyChanged("IsBusy");
                if (_isBusy)
                    base.ReportProgress();
                else
                    base.FinishProgress();
                InvalidateCommands();

            }
        }



        private bool _isEditingFishingDBs;
        public bool IsEditingFishingDbs
        {
            get
            {
                return _isEditingFishingDBs;
            }
            set
            {

                if (_isEditingFishingDBs == false && value == true)
                {
                    foreach (var item in FishingDbs)
                    {
                        (item as IEditableObject).BeginEdit();
                    }
                }

                if (_isEditingFishingDBs == true && value == false)
                {
                    foreach (var item in FishingDbs)
                    {
                        (item as IEditableObject).EndEdit();
                    }
                }
                _isEditingFishingDBs = value;
                RaisePropertyChanged("IsEditingFishingDbs");
                InvalidateCommands();
            }
        }

        private bool _isEditingProjectUser;
        public bool IsEditingProjectUser
        {
            get
            {
                return _isEditingProjectUser;
            }
            set
            {
                if (_isEditingProjectUser == false && value == true)
                {
                    foreach (var item in ProjectUser)
                    {
                        (item as IEditableObject).BeginEdit();
                    }
                }

                if (_isEditingProjectUser == true && value == false)
                {
                    foreach (var item in ProjectUser)
                    {
                        (item as IEditableObject).EndEdit();
                    }
                }
                _isEditingProjectUser = value;
                RaisePropertyChanged("IsEditingProjectUser");
                InvalidateCommands();
            }
        }


        private void InvalidateCommands()
        {

            Load.RaiseCanExecuteChanged();
            AcceptRequest.RaiseCanExecuteChanged();
            RejectRequest.RaiseCanExecuteChanged();

            EditFishingDbs.RaiseCanExecuteChanged();
            CancelEditFishingDbEdit.RaiseCanExecuteChanged();
            SaveFishingDbs.RaiseCanExecuteChanged();

            EditProjectUser.RaiseCanExecuteChanged();
            CancelEditProjectUser.RaiseCanExecuteChanged();
            SaveProjectUser.RaiseCanExecuteChanged();
            DeleteProjectUser.RaiseCanExecuteChanged();
        }


        private ObservableObjectCollection _fishingDbs = new ObservableObjectCollection();
        public ObservableObjectCollection FishingDbs
        {
            get
            {
                return _fishingDbs;
            }
            set
            {
                _fishingDbs = value;
                RaisePropertyChanged("FishingDbs");
            }
        }


        private ProjectEditViewModel _project;
        public ProjectEditViewModel Project
        {
            get
            {
                return _project;
            }
            set
            {
                _project = value;
                RaisePropertyChanged("Project");
            }
        }


        private ObservableCollection<MembershipRequestDto> _membershipRequests = new ObservableCollection<MembershipRequestDto>();
        public ObservableCollection<MembershipRequestDto> MembershipRequests
        {
            get
            {
                return _membershipRequests;
            }
            set
            {
                _membershipRequests = value;
                RaisePropertyChanged("MembershipRequests");
                RaisePropertyChanged("HasMembershipRequests");
            }
        }


        private ObservableCollection<ProjectUserDto> _projectUser = new ObservableCollection<ProjectUserDto>();
        public ObservableCollection<ProjectUserDto> ProjectUser
        {
            get
            {
                return _projectUser;
            }
            set
            {
                _projectUser = value;
                RaisePropertyChanged("ProjectUser");
            }
        }


        public bool HasMembershipRequests
        {
            get
            {
                return _membershipRequests != null && _membershipRequests.Count > 0;
            }
        }

        private INavigationService _navService;
        private IDataService _dataService;
        public SettingsViewModel(IDataService dataService, INavigationService navService)
        {
            _dataService = dataService;
            _navService = navService;
            if (IsInDesignMode)
            {
                ProjectDto p = new ProjectDto();
                p.Name = "My Project";
                p.Description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque augue arcu, porttitor sed faucibus ut, auctor at felis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam sapien metus, posuere at egestas et, iaculis ut nulla. Fusce purus ipsum, vestibulum quis ultrices et, gravida et augue. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris ornare dui at leo placerat vitae scelerisque risus pretium. Praesent eget ligula justo. Praesent id rhoncus sapien. Praesent interdum elementum pulvinar. Suspendisse potenti. Sed ligula nibh, condimentum eget aliquam sit amet, pulvinar vestibulum velit. Fusce et turpis velit.";
                ProjectEditViewModel vm = new ProjectEditViewModel(_dataService, _navService, p, false);
                Project = vm;


                IEnumerable<object> bla = "123456".ToCharArray().Select<char, object>(x =>
                                      new
                                  {
                                      Name = "Name " + x,
                                      Version = "1.0.0",
                                      Collection = "Phytozome8",
                                      IsEnabled = x == 2 || x == 4
                                  }
                                      );

                FishingDbs = new ObservableObjectCollection(bla);


            }

            _dataService.ProjectInitialized += _dataService_ProjectInitialized;
        }

        void _dataService_ProjectInitialized(object sender, EventArgs e)
        {

            //   ProjectDto p =  DataAccess.Instance.DataContext.ProjectDtos.Single(x => x.Name == DataAccess.Instance.Project.Name);
            Project = new ProjectEditViewModel(_dataService, _navService, _dataService.LoadedProject, false);

        }

        void Instance_LoadFinished(object sender, EventArgs e)
        {

        }

        private RelayCommand _load;
        public RelayCommand Load
        {
            get
            {
                return _load ?? (_load = new RelayCommand(ExecLoad, CanLoad));
            }
        }

        /// <summary>
        /// Checks whether the Load command is executable
        /// </summary>
        private bool CanLoad()
        {
            return !IsBusy;
        }


        AutoResetEvent _loadEvent = new AutoResetEvent(false);
        /// <summary>
        /// Executes the Load command 
        /// </summary>
        private void ExecLoad()
        {
            IsBusy = true;
            base.ResetError();
            ThreadPool.QueueUserWorkItem((a) =>
                {
                    var q = _dataService.DataContext.GetFishingDbsQuery(_dataService.LoadedProject.Id);
                    _dataService.DataContext.Load(q, (op) =>
                    {
                        if (op.HasError)
                        {
                            base.HandleDomainError(op, "Unable to load database information. Pleae try again.");
                        }
                        else
                        {
                            foreach (var item in op.Entities.OrderBy(x => x.DisplayName))
                            {
                                if (FishingDbs.Cast<DatabaseDto>().Any(x => x.UId == item.UId) == false)
                                    FishingDbs.Add(item);
                            }
                            foreach (var item in FishingDbs.Cast<DatabaseDto>().Select(x => x.UId).ToList())
                            {
                                if (op.Entities.Any(x => x.UId == item) == false)
                                    FishingDbs.Remove(FishingDbs.Cast<DatabaseDto>().Single(x => x.UId == item));
                            }
                        }
                        //  MessageBox.Show("1");
                        _loadEvent.Set();
                    }, null);

                    _loadEvent.WaitOne();
                    //  MessageBox.Show("2");

                    var q2 = _dataService.DataContext.GetMembershipRequestsByProjectQuery(_dataService.LoadedProject.Id);
                    _dataService.DataContext.Load<MembershipRequestDto>(q2, op =>
                    {
                        IsBusy = false;
                        if (op.HasError)
                        {
                            base.HandleDomainError(op, "Unable to load membership requests. Please try again.");
                        }
                        else
                        {
                            foreach (var item in op.Entities)
                            {
                                if (MembershipRequests.Any(x => x.UserUId == item.UserUId && x.ProjectId == item.ProjectId) == false)
                                    MembershipRequests.Add(item);
                            }
                            foreach (var item in MembershipRequests.Select(x => x.UserUId).ToList())
                            {
                                if (op.Entities.Any(x => x.UserUId == item) == false)
                                    MembershipRequests.Remove(MembershipRequests.Single(x => x.UserUId == item));
                            }
                        }
                        // MessageBox.Show("3");
                        _loadEvent.Set();
                    }, null);
                    _loadEvent.WaitOne();
                    var q3 = _dataService.DataContext.GetProjectUserQuery(_dataService.LoadedProject.Id);
                    _dataService.DataContext.Load<ProjectUserDto>(q3, op =>
                    {
                        IsBusy = false;
                        if (op.HasError)
                        {
                            base.HandleDomainError(op, "Unable to load project user. Please try again.");
                        }
                        else
                        {
                            foreach (var item in op.Entities)
                            {
                                if (ProjectUser.Any(x => x.UserUID == item.UserUID) == false)
                                    ProjectUser.Add(item);
                            }
                            foreach (var item in ProjectUser.Select(x => x.UserUID).ToList())
                            {
                                if (op.Entities.Any(x => x.UserUID == item) == false)
                                    ProjectUser.Remove(ProjectUser.Single(x => x.UserUID == item));
                            }
                        }
                        // MessageBox.Show("3");
                        _loadEvent.Set();
                    }, null);


                    _loadEvent.WaitOne();
                    // MessageBox.Show("4");
                    DispatcherHelper.CheckBeginInvokeOnUI(() =>
                        {
                            IsBusy = false;
                            RaisePropertyChanged("HasMembershipRequests");
                        });
                });


        }

        #region FishingDBS
        private RelayCommand _editFishingDBs;
        public RelayCommand EditFishingDbs
        {
            get
            {
                return _editFishingDBs ?? (_editFishingDBs = new RelayCommand(ExecEditFishingDbs, CanEditFishingDbs));
            }
        }

        /// <summary>
        /// Checks whether the EditFishingDbs command is executable
        /// </summary>
        private bool CanEditFishingDbs()
        {
            return !IsEditingFishingDbs;
        }

        /// <summary>
        /// Executes the EditFishingDbs command 
        /// </summary>
        private void ExecEditFishingDbs()
        {
            IsEditingFishingDbs = true;
        }




        private RelayCommand _cancelFishingDbEdit;
        public RelayCommand CancelEditFishingDbEdit
        {
            get
            {
                return _cancelFishingDbEdit ?? (_cancelFishingDbEdit = new RelayCommand(ExecCancelEditFishingDbEdit, CanCancelEditFishingDbEdit));
            }
        }

        /// <summary>
        /// Checks whether the CancelEditFishingDbEdit command is executable
        /// </summary>
        private bool CanCancelEditFishingDbEdit()
        {
            return IsEditingFishingDbs && !IsBusy;
        }

        /// <summary>
        /// Executes the CancelEditFishingDbEdit command 
        /// </summary>
        private void ExecCancelEditFishingDbEdit()
        {
            foreach (var item in FishingDbs)
            {
                (item as IEditableObject).CancelEdit();

            }
            IsEditingFishingDbs = false;
        }




        private RelayCommand _saveFishingDbs;
        public RelayCommand SaveFishingDbs
        {
            get
            {
                return _saveFishingDbs ?? (_saveFishingDbs = new RelayCommand(ExecSaveFishingDbs, CanSaveFishingDbs));
            }
        }

        /// <summary>
        /// Checks whether the SaveFishingDbs command is executable
        /// </summary>
        private bool CanSaveFishingDbs()
        {
            return !IsBusy && IsEditingFishingDbs;
        }

        /// <summary>
        /// Executes the SaveFishingDbs command 
        /// </summary>
        private void ExecSaveFishingDbs()
        {
            IsBusy = true;
            IsEditingFishingDbs = false;
            _dataService.SubmitAsync(op =>
                {
                    IsBusy = false;
                    if (op.HasError)
                    {
                        op.MarkErrorAsHandled();
                        MessengerInstance.Send<ErrorMessage>(new ErrorMessage(op.Error));
                    }
                    else
                    {

                    }

                });
        }

        #endregion



        #region Project User
        private RelayCommand _editProjectUser;
        public RelayCommand EditProjectUser
        {
            get
            {
                return _editProjectUser ?? (_editProjectUser = new RelayCommand(ExecEditProjectUser, CanEditProjectUser));
            }
        }

        /// <summary>
        /// Checks whether the EditProjectUser command is executable
        /// </summary>
        private bool CanEditProjectUser()
        {
            return !IsEditingProjectUser;
        }

        /// <summary>
        /// Executes the EditProjectUser command 
        /// </summary>
        private void ExecEditProjectUser()
        {

            IsEditingProjectUser = true;
        }



        private RelayCommand _cancelEditProjectUser;
        public RelayCommand CancelEditProjectUser
        {
            get
            {
                return _cancelEditProjectUser ?? (_cancelEditProjectUser = new RelayCommand(ExecCancelEditProjectUser, CanCancelEditProjectUser));
            }
        }

        /// <summary>
        /// Checks whether the CancelEditProjectUser command is executable
        /// </summary>
        private bool CanCancelEditProjectUser()
        {
            return !IsBusy && IsEditingProjectUser;
        }

        /// <summary>
        /// Executes the CancelEditProjectUser command 
        /// </summary>
        private void ExecCancelEditProjectUser()
        {
            foreach (var item in ProjectUser)
            {
                (item as IEditableObject).CancelEdit();
            }
            IsEditingProjectUser = false;
        }


        private RelayCommand _saveProjectUser;
        public RelayCommand SaveProjectUser
        {
            get
            {
                return _saveProjectUser ?? (_saveProjectUser = new RelayCommand(ExecSaveProjectUser, CanSaveProjectUser));
            }
        }

        /// <summary>
        /// Checks whether the SaveProjectUser command is executable
        /// </summary>
        private bool CanSaveProjectUser()
        {
            return !IsBusy && IsEditingProjectUser;
        }

        /// <summary>
        /// Executes the SaveProjectUser command 
        /// </summary>
        private void ExecSaveProjectUser()
        {
            IsBusy = true;
            IsEditingProjectUser = false;
            _dataService.SubmitAsync(op =>
            {
                IsBusy = false;
                if (op.HasError)
                {
                    op.MarkErrorAsHandled();
                    MessengerInstance.Send<ErrorMessage>(new ErrorMessage(op.Error));
                }
                else
                {

                }

            });
        }



        private RelayCommand<ProjectUserDto> _deleteProjectUser;
        public RelayCommand<ProjectUserDto> DeleteProjectUser
        {
            get
            {

                return _deleteProjectUser ?? (_deleteProjectUser = new RelayCommand<ProjectUserDto>(ExecDeleteProjectUser, CanDeleteProjectUser));

            }
        }

        /// <summary>
        /// Checks whether the DeleteProjectUser command is executable
        /// </summary>
        private bool CanDeleteProjectUser(ProjectUserDto val)
        {
            return !IsBusy;
        }

        /// <summary>
        /// Executes the DeleteProjectUser command 
        /// </summary>
        private void ExecDeleteProjectUser(ProjectUserDto val)
        {
            base.ConfirmAction(doit =>
                   {
                       if (doit)
                       {
                           IsBusy = true;
                           (val as IEditableObject).CancelEdit();
                           _dataService.DataContext.ProjectUserDtos.Remove(val);

                           _dataService.SubmitAsync(op =>
                           {
                               IsBusy = false;
                               if (op.HasError)
                               {
                                   op.MarkErrorAsHandled();
                                   MessengerInstance.Send<ErrorMessage>(new ErrorMessage(op.Error));
                               }
                               else
                               {
                                   ProjectUser.Remove(val);
                               }

                           });
                       }
                   }
            , "You are about to delete the user '" + val.Username + "' from your project.");

        }
        
        #endregion



        #region Requests
        private RelayCommand<MembershipRequestDto> _acceptRequest;
        public RelayCommand<MembershipRequestDto> AcceptRequest
        {
            get
            {
                return _acceptRequest ?? (_acceptRequest = new RelayCommand<MembershipRequestDto>(ExecAcceptRequest, CanAcceptRequest));
            }
        }

        /// <summary>
        /// Checks whether the AcceptRequest command is executable
        /// </summary>
        private bool CanAcceptRequest(MembershipRequestDto val)
        {
            return !IsBusy;
        }

        /// <summary>
        /// Executes the AcceptRequest command 
        /// </summary>
        private void ExecAcceptRequest(MembershipRequestDto val)
        {
            IsBusy = true;
            _dataService.DataContext.GrantMembership(val, op =>
                {
                    IsBusy = false;
                    if (op.HasError)
                    {
                        op.MarkErrorAsHandled();
                        MessengerInstance.Send<ErrorMessage>(new ErrorMessage(op.Error));
                    }
                    else
                    {
                        MembershipRequests.Remove(val);
                        ProjectUser.Add(op.Value);
                    }
                    RaisePropertyChanged("HasMembershipRequests");
                }, null);
        }


        private RelayCommand<MembershipRequestDto> _rejectRequest;
        public RelayCommand<MembershipRequestDto> RejectRequest
        {
            get
            {
                return _rejectRequest ?? (_rejectRequest = new RelayCommand<MembershipRequestDto>(ExecRejectRequest, CanRejectRequest));
            }
        }

        /// <summary>
        /// Checks whether the RejectRequest command is executable
        /// </summary>
        private bool CanRejectRequest(MembershipRequestDto val)
        {
            return true;
        }

        /// <summary>
        /// Executes the RejectRequest command 
        /// </summary>
        private void ExecRejectRequest(MembershipRequestDto val)
        {
            IsBusy = true;
            _dataService.DataContext.RejectMembership(val, op =>
            {
                IsBusy = false;
                if (op.HasError)
                {
                    op.MarkErrorAsHandled();
                    MessengerInstance.Send<ErrorMessage>(new ErrorMessage(op.Error));
                }
                else
                {
                    MembershipRequests.Remove(val);
                }
                RaisePropertyChanged("HasMembershipRequests");
            }, null);
        }
        #endregion


        private RelayCommand _import;
        public RelayCommand Import
        {
            get
            {
                return _import ?? (_import = new RelayCommand(ExecImport, CanImport));
            }
        }

        /// <summary>
        /// Checks whether the Import command is executable
        /// </summary>
        private bool CanImport()
        {
            return true;
        }

        /// <summary>
        /// Executes the Import command 
        /// </summary>
        private void ExecImport()
        {
            _navService.Navigate(NavigationTargets.Import);
        }


    }
}
